package random

import (
	"math"
	"math/rand"
	"time"

	"github.com/spf13/cast"
)

// Constants definition
const (
	randomLimit = 10000
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

// Round eg:Round(1.056,2) => 1.06, Round(1.054,2)=>1.054
func Round64(f float64, n int) float64 {
	pow10_n := math.Pow10(n)
	return math.Trunc((f+0.5/pow10_n)*pow10_n) / pow10_n
}

func Round32(f float32, n int) float32 {
	pow10_n := math.Pow10(n)
	return float32(math.Trunc((float64(f)+0.5/pow10_n)*pow10_n) / pow10_n)
}

// Hit returns if probability > a random number range [0,10000)
func Hit(probability int) bool {
	rand.Seed(time.Now().UnixNano())
	return Intn(randomLimit) < probability
}

// Intn returns a random number in [0,limit)
func Intn(limit int) int {
	return rand.Intn(limit)
}

// Int31 method
func Int31() int32 {
	return rand.Int31()
}

// Int31n method
func Int31n(limit interface{}) int32 {
	return rand.Int31n(cast.ToInt32(limit))
}

// Perm method: generate different order [0, limit) slice
func Perm(limit int, seed int64) []int {
	rand.Seed(seed)
	return rand.Perm(limit)
}

// RangeFloat32 返回[min, max]之间的float32
// 放大factor倍后用Int63n随机
func RangeFloat32(min, max float32) float32 {
	if max < min {
		return 0
	}

	if min == max {
		return min
	}

	factor := float32(100000000) // 假定float32精度最大为8
	intMin := int64(min * factor)
	intMax := int64(max * factor)
	randInt := rand.Int63n(intMax-intMin+1) + intMin

	r := Round32(float32(randInt)/factor, 2)
	return r
}

// ChooseWeightItem choose one index from giving array 'candidates'
func ChooseWeightItem(candidates []int, luckyValue int32) int {
	// 去掉幸运值对于drop的影响
	luckyValue = 0
	lastIndex := len(candidates) - 1
	if lastIndex < 0 {
		return -1
	}
	maxValue := candidates[lastIndex]
	rValue := Intn(maxValue) + (int(luckyValue) * maxValue / randomLimit)

	// 因为数组已排序,改为二分法查找
	left, right := 0, lastIndex
	for left <= right {
		middle := (left + right) >> 1
		value := candidates[middle]
		if value > rValue {
			right = middle - 1
		} else if value <= rValue {
			left = middle + 1
		}
	}
	if left <= lastIndex {
		return left
	}

	return lastIndex
}

// 生成count个[start,end)结束的不重复的随机数
func GenerateRandomNumber(start int, end int, count int, seed int64) []int {
	// 范围检查
	if end < start || (end-start) < count {
		return nil
	}

	// 存放结果的slice
	nums := make([]int, 0)
	// 随机数生成器，加入时间戳保证每次生成的随机数不一样
	r := rand.New(rand.NewSource(seed))
	for len(nums) < count {
		// 生成随机数
		num := r.Intn((end - start)) + start

		// 查重
		exist := false
		for _, v := range nums {
			if v == num {
				exist = true
				break
			}
		}

		if !exist {
			nums = append(nums, num)
		}
	}

	return nums
}

// 在[start,end]之间随机生成一个数
func RangeInt(start int, end int, seed int64) int {
	if end <= start {
		return start
	}

	// 随机数生成器，加入时间戳保证每次生成的随机数不一样
	r := rand.New(rand.NewSource(seed))
	// 生成随机数
	return r.Intn((end + 1 - start)) + start
}

// 在[start,end]之间随机生成一个不等于without的数
func RangeIntWithout(start int, end int, seed int64, without int, i int32) int {
	if i > 10 {
		return 0
	}

	if end <= start {
		return start
	}

	r := RangeInt(start, end, seed)
	if r == without {
		r = RangeIntWithout(start, end, seed, without, i+1)
	}

	return r
}
func Drop(d map[int32]int32) (key int32) {
	randomNum := int32(RangeInt(1, 10000, 1))
	for k, v := range d {
		if randomNum > v {
			randomNum -= v
			continue
		}
		return k
	}
	return 0
}
